home *** CD-ROM | disk | FTP | other *** search
/ Aminet 4 / Aminet 4 - November 1994.iso / aminet / dev / gcc / libnix.lha / gnu / lib / libnix / sources.lha / nix / stdio / vfscanf.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-06-26  |  9.3 KB  |  382 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <stdarg.h>
  4. #include <limits.h>
  5. #include <ctype.h>
  6. #include <math.h>
  7.  
  8. /* some macros to cut this short
  9.  * NEXT(c);     read next character
  10.  * PREV(c);     ungetc a character
  11.  * VAL(a)       leads to 1 if a is true and valid
  12.  */
  13. #define NEXT(c) ((c)=fgetc(stream),size++,incount++)
  14. #define PREV(c) do{if((c)!=EOF)ungetc((c),stream);size--;incount--;}while(0)
  15. #define VAL(a)  ((a)&&size<=width)
  16.  
  17. extern unsigned char *__decimalpoint;
  18. extern unsigned char __undef[][sizeof(double)];
  19.  
  20. int vfscanf(FILE *stream,const char *format,va_list args)
  21. {
  22.   size_t blocks=0,incount=0;
  23.  
  24.   while(*format)
  25.   { int c;
  26.     size_t size=0;
  27.       
  28.     if(*format=='%')
  29.     {
  30.       size_t width=ULONG_MAX;
  31.       char type,subtype='i',ignore=0;
  32.       const unsigned char *ptr=format+1;
  33.       size_t i;
  34.  
  35.       if(isdigit(*ptr))
  36.       { width=0;
  37.         while(isdigit(*ptr))
  38.           width=width*10+(*ptr++-'0'); }
  39.  
  40.       while(*ptr=='h'||*ptr=='l'||*ptr=='L'||*ptr=='*')
  41.       { if(*ptr=='*')
  42.           ignore=1;
  43.         else
  44.           subtype=*ptr;
  45.         ptr++; 
  46.       }
  47.  
  48.       type=*ptr++;
  49.  
  50.       if(type&&type!='%'&&type!='c'&&type!='n'&&type!='[')
  51.       { do /* ignore leading whitespace characters */
  52.           NEXT(c);
  53.         while(isspace(c));
  54.         size=1; } /* The first non-whitespace character is already read */
  55.  
  56.       switch(type)
  57.       { case 'c':
  58.         { unsigned char *bp;
  59.  
  60.           if(width==ULONG_MAX) /* Default */
  61.             width=1;
  62.  
  63.           if(!ignore)
  64.             bp=va_arg(args,char *);
  65.           else
  66.             bp=NULL; /* Just to get the compiler happy */
  67.  
  68.           NEXT(c); /* 'c' did not skip whitespace */
  69.           while(VAL(c!=EOF))
  70.           { if(!ignore)
  71.               *bp++=c;
  72.             NEXT(c);
  73.           }
  74.           PREV(c);
  75.  
  76.           if(!ignore&&size)
  77.             blocks++;
  78.           break;
  79.         }
  80.         case '[':
  81.         { unsigned char *bp;
  82.           unsigned char tab[32],a,b;
  83.           char circflag=0;
  84.           
  85.           if(*ptr=='^')
  86.           { circflag=1;
  87.             ptr++; }
  88.           for(i=0;i<sizeof(tab);i++)
  89.             tab[i]=circflag?255:0;
  90.           do
  91.           { if(!*ptr)
  92.               break;
  93.             a=*ptr++;
  94.             if(*ptr=='-'&&ptr[1]>a)
  95.             { ptr++;
  96.               b=*ptr++;
  97.             }else
  98.               b=a;
  99.             for(i=a;i<=b;i++)
  100.               if(circflag)
  101.                 tab[i/8]&=~(1<<(i&7));
  102.               else
  103.                 tab[i/8]|=1<<(i&7);
  104.           }while(*ptr!=']');
  105.  
  106.           if(!ignore)
  107.             bp=va_arg(args,char *);
  108.           else
  109.             bp=NULL; /* Just to get the compiler happy */
  110.  
  111.           NEXT(c);
  112.           while(VAL(c!=EOF&&tab[c/8]&(1<<(c&7))))
  113.           { if(!ignore)
  114.               *bp++=c;
  115.             NEXT(c);
  116.           }
  117.           PREV(c);
  118.  
  119.           if(!ignore&&size)
  120.           { *bp++='\0';
  121.             blocks++; }
  122.           break;
  123.         }
  124.         case 's':
  125.         { unsigned char *bp;
  126.             
  127.           if(!ignore)
  128.             bp=va_arg(args,char *);
  129.           else
  130.             bp=NULL; /* Just to get the compiler happy */
  131.  
  132.           while(VAL(c!=EOF&&!isspace(c)))
  133.           { if(!ignore)
  134.               *bp++=c;
  135.             NEXT(c);
  136.           }
  137.           PREV(c);
  138.  
  139.           if(!ignore&&size)
  140.           { *bp++='\0';
  141.             blocks++; }
  142.           break;
  143.         }
  144. #ifdef FULL_SPECIFIERS
  145.         case 'e':
  146.         case 'f':
  147.         case 'g':
  148.         { double v;
  149.           int ex=0;
  150.           int min=0,mine=0; /* This is a workaround for gcc 2.3.3: should be char */
  151.  
  152.           do /* This is there just to be able to break out */
  153.           {
  154.             if(VAL(c=='-'||c=='+'))
  155.             { min=c;
  156.               NEXT(c); }
  157.  
  158.             if(VAL(tolower(c)=='i')) /* +- inf */
  159.             { int d;
  160.               NEXT(d);
  161.               if(VAL(tolower(d)=='n'))
  162.               { int e;
  163.                 NEXT(e);
  164.                 if(VAL(tolower(e)=='f'))
  165.                 { v=*(double *)&__undef[min=='-'];
  166.                   break; } /* break out */
  167.                 PREV(e);
  168.               }
  169.               PREV(d);
  170.             }
  171.             else if(VAL(toupper(c)=='N')) /* NaN */
  172.             { int d;
  173.               NEXT(d);
  174.               if(VAL(tolower(d)=='a'))
  175.               { int e;
  176.                 NEXT(e);
  177.                 if(VAL(toupper(e)=='N'))
  178.                 { v=*(double *)&__undef[2];
  179.                   break; }
  180.                 PREV(e);
  181.               }
  182.               PREV(d);
  183.             }
  184.  
  185.             v=0.0;
  186.             while(VAL(isdigit(c)))
  187.             { v=v*10.0+(c-'0');
  188.               NEXT(c);
  189.             }
  190.  
  191.             if(VAL(c==__decimalpoint[0]))
  192.             { double dp=0.1;
  193.               NEXT(c);
  194.               while(VAL(isdigit(c)))
  195.               { v=v+dp*(c-'0');
  196.                 dp=dp/10.0;
  197.                 NEXT(c); }
  198.               if(size==2+(min!=0)) /* No number read till now -> malformatted */
  199.               { PREV(c);
  200.                 c=__decimalpoint[0]; }
  201.             }
  202.  
  203.             if(size==1+(min!=0)) /* No number read till now -> malformatted */
  204.             { PREV(c);
  205.               if(min)
  206.                 PREV(min);
  207.               break; }
  208.  
  209.             if(VAL(tolower(c)=='e'))
  210.             { int d;
  211.               NEXT(d);
  212.               if(VAL(d=='-'||d=='+'))
  213.               { mine=d;
  214.                 NEXT(d); }
  215.  
  216.               if(VAL(isdigit(d)))
  217.               { do
  218.                 { ex=ex*10+(d-'0');
  219.                   NEXT(d);
  220.                 }while(VAL(isdigit(d)&&ex<100));
  221.                 c=d;
  222.               }else
  223.               { PREV(d);
  224.                 if(mine)
  225.                   PREV(mine);
  226.               }
  227.             }
  228.             PREV(c);
  229.  
  230.             if(mine=='-')
  231.               v=v/pow(10.0,ex);
  232.             else
  233.               v=v*pow(10.0,ex);
  234.  
  235.             if(min=='-')
  236.               v=-v;
  237.  
  238.           }while(0);
  239.  
  240.           if(!ignore&&size)
  241.           { switch(subtype)
  242.             { case 'l':
  243.               case 'L':
  244.                 *va_arg(args,double *)=v;
  245.                 break;
  246.               case 'i':
  247.                 *va_arg(args,float *)=v;
  248.                 break;
  249.             }
  250.             blocks++;
  251.           }
  252.           break;
  253.         }
  254. #endif
  255.         case '%':
  256.           NEXT(c);
  257.           if(c!='%')
  258.             PREV(c); /* unget non-'%' character */
  259.           break;
  260.         case 'n':
  261.           if(!ignore)
  262.             *va_arg(args,int *)=incount;
  263.           size=1; /* fake a valid argument */
  264.           blocks++;
  265.           break;
  266.         default:
  267.         { unsigned long v=0;
  268.           int base;
  269.           int min=0;
  270.  
  271.           if(!type)
  272.             ptr--; /* unparse NUL character */
  273.  
  274.           if(type=='p')
  275.           { subtype='l'; /* This is the same as %lx */
  276.             type='x'; }
  277.  
  278.           if(VAL((c=='-'&&type!='u')||c=='+'))
  279.           { min=c;
  280.             NEXT(c); }
  281.  
  282.           if(type=='i') /* which one to use ? */
  283.           { if(VAL(c=='0')) /* Could be octal or sedecimal */
  284.             { int d;
  285.               NEXT(d); /* Get a look at next character */
  286.               if(VAL(tolower(d)=='x'))
  287.               { int e;
  288.                 NEXT(e); /* And the next */
  289.                 if(VAL(isxdigit(c)))
  290.                   type='x'; /* Is a valid x number with '0x?' */
  291.                 PREV(e);
  292.               }else
  293.                 type='o';
  294.               PREV(d);
  295.             }else if(VAL(!isdigit(c)&&isxdigit(c)))
  296.               type='x'; /* Is a valid x number without '0x' */
  297.           }
  298.             
  299.           while(type=='x'&&VAL(c=='0')) /* sedecimal */
  300.           { int d;
  301.             NEXT(d);
  302.             if(VAL(tolower(d)=='x'))
  303.             { int e;
  304.               NEXT(e);
  305.               if(VAL(isxdigit(e)))
  306.               { c=e;
  307.                 break; } /* Used while just to do this ;-) */
  308.               PREV(e);
  309.             }
  310.             PREV(d);
  311.             break; /* Need no loop */
  312.           }
  313.  
  314.           base=type=='x'||type=='X'?16:(type=='o'?8:10);
  315.           while(VAL(isxdigit(c)&&(base!=10||isdigit(c))&&(base!=8||c<='7')))
  316.           { v=v*base+(isdigit(c)?c-'0':0)+(isupper(c)?c-'A'+10:0)+(islower(c)?c-'a'+10:0);
  317.             NEXT(c);
  318.           }
  319.           PREV(c);
  320.  
  321.           if(min&&size==1) /* If there is no valid character, unget sign */
  322.             PREV(min);
  323.           if(ignore||!size)
  324.             break;
  325.  
  326.           if(type=='u')
  327.             switch(subtype)
  328.             { case 'l':
  329.               case 'L':
  330.                 *va_arg(args,unsigned long *)=v;
  331.                 break;
  332.               case 'i':
  333.                 *va_arg(args,unsigned int *)=v;
  334.                 break;
  335.               case 'h':
  336.                 *va_arg(args,unsigned short *)=v;
  337.                 break;
  338.             }
  339.           else
  340.           { signed long v2;
  341.             if(min=='-')
  342.               v2=-v;
  343.             else
  344.               v2=v;
  345.             switch(subtype)
  346.             { case 'l':
  347.               case 'L':
  348.                 *va_arg(args,signed long *)=v2;
  349.                 break;
  350.               case 'i':
  351.                 *va_arg(args,signed int *)=v2;
  352.                 break;
  353.               case 'h':
  354.                 *va_arg(args,signed short *)=v2;
  355.                 break;
  356.             }
  357.           }
  358.           blocks++;
  359.           break;
  360.         }
  361.       }
  362.       format=ptr;
  363.     }else
  364.     { if(isspace(*format))
  365.       { do
  366.           NEXT(c);
  367.         while(isspace(c));
  368.         PREV(c);
  369.         size=1; }
  370.       else
  371.       { NEXT(c);
  372.         if(c!=*format)
  373.           PREV(c); }
  374.       format++;
  375.     }
  376.     if(!size)
  377.       return blocks;
  378.   }
  379.  
  380.   return blocks;
  381. }
  382.